home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacHack 1997
/
MacHack 1997.toast
/
Hacks
/
Hacks ’95
/
TrashAddition
/
TrashAddition.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-10
|
11KB
|
453 lines
// This is a sample drag strip addition. The purpose is to correct the behavior
// that DS has when an alias of the trash is placed on it.
// This demonstrates sending an apple event, looping through mounted volumes,
// plotting an icon family, ejecting/unmounting volumes, moving items to the
// trash, and other DragStrip™ addition API features.
// Revisions
// Author Date Comment
// ------------ ------------- ------------------------------------------
// JGB MacHack '95 First revision
#include <Palettes.h>
#include <GestaltEqu.h>
#include <Icons.h>
#include <AppleEvents.h>
#include <A4Stuff.h>
#include <Files.h>
#include <Strings.h>
#include "DS Additions.h"
#include "Drag.h"
#define ScreenDepth(gdh) ((*((*gdh)->gdPMap))->pixelSize)
pascal long main( DSAdditionParamBlockPtr params)
{
long result = 0;
Rect localRect;
Point mousePoint;
OSErr theErr, iErr;
long iconID ;
long oldA4 = SetCurrentA4();
AppleEvent theAppleEvent ;
switch(params->dsMessage)
{
// -------------------------------------------------------
// Given an Init or Close message, do what we need to
// -------------------------------------------------------
case kMsgInitAddition:
params->dsRefCon = (long)NewHandle(10); //Allocate some memory for some reason
result = MemError();
InitAppleEvents();
break;
case kMsgCloseAddition:
if(params->dsRefCon != nil)
{
DisposeHandle((Handle)params->dsRefCon);
}
break;
// -------------------------------------------------------
// Given a draw or hilite message, draw what we need into
// the provided rectangle
// -------------------------------------------------------
case kMsgDraw:
case kMsgDrawHilite:
localRect = params->dsIconRect;
iconID = GetTrashIcon() ;
PlotIconID( &localRect ,
atBottom + atVerticalCenter ,
ttNone ,
iconID );
params->dsNextDrawTime = TickCount() + (60 * 3); //Draw again in 3 seconds
break;
// -------------------------------------------------------
// Given a hit message, do whatever we do when we are hit
// -------------------------------------------------------
case kMsgHit:
localRect = params->dsLocalRect;
GetMouse( &mousePoint );
// Make sure that the user actually let go inside the rect
// before doing our thing.
while(StillDown() && PtInRect(mousePoint, &localRect)) {
GetMouse(&mousePoint);
}
if( ! StillDown() )
{
OSType fndrSig = 'MACS';
AEAddressDesc target ;
AECreateDesc( typeApplSignature ,
&fndrSig ,
sizeof( fndrSig ) ,
&target );
iErr = AECreateAppleEvent( kAEFinderEvents,
'empt',
&target,
kAutoGenerateReturnID,
kAnyTransactionID,
&theAppleEvent );
iErr = AESend( &theAppleEvent,
nil,
kAENoReply + kAECanInteract,
kAENormalPriority,
3600,
nil,
nil );
AEDisposeDesc( &target );
AEDisposeDesc( &theAppleEvent );
}
break;
// -------------------------------------------------------
// Given a drop message, pull the files out of the
// DragReference then do what you want with them.
// -------------------------------------------------------
case kMsgDropOccurred:
{
unsigned short items, index, flavors, j ;
ItemReference theItemRef ;
FlavorType theType ;
HFSFlavor flavorData ;
Size dataSize ;
unsigned long dataOffset = 0;
CountDragItems( params->dsDragReference, &items );
for (index = 1; index <= items; index++)
{
iErr = GetDragItemReferenceNumber( params->dsDragReference,
index,
&theItemRef );
iErr = CountDragItemFlavors( params->dsDragReference,
theItemRef,
&flavors );
for( j = 1 ; j <= flavors ; j++)
{
iErr = GetFlavorType( params->dsDragReference,
theItemRef,
j,
&theType );
switch( theType )
{
case 'hfs ': // We an HFS Flavor was dropped on us
// Move this puppy to the trash
iErr = GetFlavorDataSize( params->dsDragReference,
theItemRef,
theType,
&dataSize);
iErr = GetFlavorData( params->dsDragReference,
theItemRef,
theType,
&flavorData,
&dataSize,
dataOffset );
TrashItem( flavorData );
break;
}
}
}
break;
}
}
SetA4(oldA4);
return result;
}
// ------------------------------------------------------------------
// GetTrashIcon
//
// Based on the current state of the trash on all volumes, return the
// resource ID of the icon to plot.
// ------------------------------------------------------------------
long GetTrashIcon ( void )
{
VolumeParam paramBlock ;
CInfoPBRec pb ;
Str255 volName , dirName ;
OSErr checkErr , theErr ;
long trashFiles ;
short i = 1 ;
short volRefNo , trashVRefNo ;
long trashDirID ;
long iconID = -3993 ;
theErr = noErr ;
// Walk through all mounted volumes
for( i = 1 ; theErr == noErr ; i++)
{
paramBlock.ioVolIndex = i ;
paramBlock.ioNamePtr = volName ;
paramBlock.ioVRefNum = volRefNo ;
theErr = PBGetVInfo( (ParmBlkPtr) ¶mBlock , FALSE ) ;
volRefNo = paramBlock.ioVRefNum ;
if( theErr == noErr )
{
checkErr = FindFolder( volRefNo ,
kTrashFolderType ,
kDontCreateFolder ,
&trashVRefNo ,
&trashDirID );
pb.dirInfo.ioVRefNum = volRefNo ;
pb.dirInfo.ioFDirIndex = -1 ;
pb.dirInfo.ioNamePtr = dirName ;
pb.dirInfo.ioDrDirID = trashDirID ;
checkErr = PBGetCatInfo( &pb , FALSE );
trashFiles = pb.dirInfo.ioDrNmFls ;
// If the trash folder has any items, return # and break
if( trashFiles > 0 )
{
iconID = -3984 ;
theErr = nsvErr ;
}
}
}
return iconID ;
}
// ------------------------------------------------------------------
// InitAppleEvents
//
// Initialize AppleEvent sender. Beep and return 1 if not supported.
// ------------------------------------------------------------------
long InitAppleEvents( void )
{
long feature, result = 0 ;
OSErr err ;
err = Gestalt( gestaltAppleEventsAttr, &feature );
if( err != noErr )
{
SysBeep( 10 );
result = 1 ;
}
return result;
}
// ------------------------------------------------------------------
// TrashItem
//
// Send this "thing" to hell!
// ------------------------------------------------------------------
void TrashItem( HFSFlavor hfsFlavor )
{
OSErr result = noErr;
ParamBlockRec paramBlock ;
Str255 pathName ;
if((hfsFlavor.fileType == 'disk') && (hfsFlavor.fileCreator == 'MACS')) //Don't unmount the startup volume
{
if (hfsFlavor.fileSpec.vRefNum != -1) // This is a drive
{
short driveNumber;
driveNumber = GetDriveNumber(hfsFlavor.fileSpec.vRefNum);
result = UnmountVol(nil, hfsFlavor.fileSpec.vRefNum);
if(result == noErr)
{
result = Eject(nil, driveNumber);
}
}
else {
result = -50;
}
}
else // We are trashing an actual file or folder
{
FSSpec trashFolder;
FInfo fndrInfo;
Str63 newName = "\p" ;
char addName ;
short strLen , copyIDPos ;
if(result == noErr && MakeSpecialFolderFSSpec(hfsFlavor.fileSpec.vRefNum, &trashFolder, kTrashFolderType))
{
result = FSpCatMove( &hfsFlavor.fileSpec , &trashFolder);
if( result == dupFNErr )
{
// there is already an item named this in the trash - how often does this happen anyway?
short i;
strLen = hfsFlavor.fileSpec.name[0] ;
copyIDPos = strLen + 1 ;
if( copyIDPos > 62 ) copyIDPos = 62 ;
for (i = 1 ; result == dupFNErr ; i++ )
{
addName = (char)(i+(short)'a') ;
BlockMove( &hfsFlavor.fileSpec.name[1] , &newName[1] , strLen );
BlockMove( &addName , &newName[copyIDPos] , 1 );
newName[0] = copyIDPos;
result = FSpRename( &hfsFlavor.fileSpec , newName );
BlockMove( newName , &hfsFlavor.fileSpec.name , copyIDPos + 1 );
result = FSpCatMove( &hfsFlavor.fileSpec , &trashFolder);
}
}
UpdateParentFolderModDate( &hfsFlavor.fileSpec );
}
}
}
// ------------------------------------------------------------------
// MakeSpecialFolderFSSpec
//
// Courtesy of Chris Evans
// Return a finder folder's FSSpec
// ------------------------------------------------------------------
Boolean MakeSpecialFolderFSSpec(short vRefNum, FSSpec *folderSpec, OSType folder)
{
short folderVRefNum;
long folderDirID;
OSErr theErr;
Boolean result = false;
if(FindFolder(vRefNum, folder, kCreateFolder, &folderVRefNum, &folderDirID) == noErr)
{
CInfoPBRec thePB;
folderSpec->name[0] = 0;
thePB.dirInfo.ioCompletion = 0L;
thePB.dirInfo.ioNamePtr = (StringPtr) &folderSpec->name;
thePB.dirInfo.ioVRefNum = folderVRefNum;
thePB.dirInfo.ioFDirIndex = -1;
thePB.dirInfo.ioDrDirID = folderDirID;
theErr = PBGetCatInfo(&thePB, false);
if(theErr == noErr )
{
folderSpec->parID = thePB.dirInfo.ioDrParID;
folderSpec->vRefNum = folderVRefNum;
result = true;
}
}
return result;
}
// ------------------------------------------------------------------
// GetDriveNumber
//
// Courtesy of Chris Evans
// Return a finder folder's FSSpec
// ------------------------------------------------------------------
short GetDriveNumber( short vRefNum )
{
QHdrPtr qhp;
VCB *vcbp;
qhp = GetVCBQHdr(); // Address of queue header
vcbp = ( VCB *) qhp->qHead;
while( vcbp )
{
if( vcbp->vcbVRefNum == vRefNum )
{
return vcbp->vcbDrvNum;
}
vcbp = (VCB *)vcbp->qLink;
}
return -1;
}
// ------------------------------------------------------------------
// UpdateFolderModDate
//
// Update a folder so the finder redraws it.
// ------------------------------------------------------------------
void UpdateParentFolderModDate( FSSpec *theSpec )
{
CInfoPBRec pb;
OSErr theErr;
pb.dirInfo.ioCompletion = nil;
pb.dirInfo.ioNamePtr = nil;
pb.dirInfo.ioVRefNum = theSpec->vRefNum;
pb.dirInfo.ioFDirIndex = -1;
pb.dirInfo.ioDrDirID = theSpec->parID;
theErr = PBGetCatInfo(&pb, false);
if(theErr == noErr)
{
pb.dirInfo.ioDrMdDat = LMGetTime();
pb.dirInfo.ioDrDirID = theSpec->parID;
PBSetCatInfo(&pb, false);
}
}